package com.ext.aic.handler;

import android.content.Context;
import android.text.TextUtils;

import androidx.lifecycle.LifecycleOwner;

import com.ext.aic.apis.user.LoginRequest;
import com.ext.aic.apis.user.LoginService;
import com.ext.aic.apis.user.RefreshTokenRequest;
import com.ext.aic.apis.user.RegisterRequest;
import com.ext.aic.beans.UserInfo;
import com.ext.aic.beans.params.LoginParams;
import com.ext.aic.beans.params.RefreshTokenParams;
import com.ext.aic.beans.params.RegisterParams;
import com.ext.aic.beans.response.ExceptionResponse;
import com.ext.aic.beans.response.LoginItem;
import com.ext.aic.beans.response.RefreshTokenResponse;
import com.ext.aic.beans.response.RegisterResponse;
import com.ext.aic.constants.ApiConstants;
import com.ext.aic.constants.CacheConstants;
import com.ext.aic.utils.UserUtils;
import com.ext.aic.utils.device.DeviceUtils;
import com.eyinfo.android_pure_utils.events.Action0;
import com.eyinfo.android_pure_utils.executor.CycleExecutor;
import com.eyinfo.mpkv.MPLocalKV;

//用户授权
public class AuthorizationHandler {

    private LifecycleOwner lifecycleOwner;
    private Context context;
    private long lastCheckTime;
    private boolean tokenInRenewal = false;
    private long checkPeriod = 25 * 60 * 1000;

    private void requestRegister(String userName, Action0 successCall, Action0 reAuditCall) {
        RegisterParams registerParams = new RegisterParams();
        registerParams.setDeviceId(DeviceUtils.getInstance().getDeviceId(context));
        registerParams.setUsername(userName);
        registerParams.setPassword(getUserPassword());
        registerParams.setDisplayName(userName);
        registerRequest.setSuccessCall(successCall);
        registerRequest.setReAuditCall(reAuditCall);
        registerRequest.request(context, lifecycleOwner, registerParams);
    }

    private LoginRequest<Boolean> loginRequest = new LoginRequest<Boolean>() {
        @Override
        protected void onLoginSuccess(LoginItem loginResponse, LoginParams loginParams, Boolean extra) {
            if (TextUtils.equals(loginResponse.getStatus(), "pass")) {
                MPLocalKV.getInstance().put(CacheConstants.INSTALL_LICENSE_STATUS_KEY, true);
            } else {
                MPLocalKV.getInstance().put(CacheConstants.INSTALL_LICENSE_STATUS_KEY, false);
            }
            UserInfo userInfo = new UserInfo();
            userInfo.setUserId(loginResponse.getUserId());
            userInfo.setUserName(loginParams.getUsername());
            userInfo.setNick(loginParams.getUsername());
            userInfo.setAccessToken(loginResponse.getAccessToken());
            userInfo.setRefreshToken(loginResponse.getRefreshToken());
            userInfo.setExpiresIn(loginResponse.getExpiresIn());
            userInfo.setLoginTime(System.currentTimeMillis());
            UserUtils.getInstance().saveUserInfo(userInfo);
            Action0 successCall = super.getSuccessCall();
            if (successCall != null) {
                successCall.call();
            }
        }

        @Override
        protected void onFail(ExceptionResponse response, LoginParams loginParams, Boolean extra) {
            if (extra == null || !extra) {
                if (response.getCode() == ApiConstants.unregister) {
                    requestRegister(loginParams.getUsername(), getSuccessCall(), getReAuditCall());
                } else {
                    UserUtils.getInstance().clear();
                }
            }
        }
    };

    private LoginService<Boolean> loginService = new LoginService<Boolean>() {
        @Override
        protected void onLoginSuccess(LoginItem loginResponse, LoginParams loginParams, Boolean extra) {
            if (TextUtils.equals(loginResponse.getStatus(), "pass")) {
                MPLocalKV.getInstance().put(CacheConstants.INSTALL_LICENSE_STATUS_KEY, true);
            } else {
                MPLocalKV.getInstance().put(CacheConstants.INSTALL_LICENSE_STATUS_KEY, false);
            }
            UserInfo userInfo = new UserInfo();
            userInfo.setUserId(loginResponse.getUserId());
            userInfo.setUserName(loginParams.getUsername());
            userInfo.setNick(loginParams.getUsername());
            userInfo.setAccessToken(loginResponse.getAccessToken());
            userInfo.setRefreshToken(loginResponse.getRefreshToken());
            userInfo.setExpiresIn(loginResponse.getExpiresIn());
            userInfo.setLoginTime(System.currentTimeMillis());
            UserUtils.getInstance().saveUserInfo(userInfo);
            Action0 successCall = super.getSuccessCall();
            if (successCall != null) {
                successCall.call();
            }
        }

        @Override
        protected void onLoginFail(LoginParams loginParams, Boolean extra) {
//            if (extra == null || !extra) {
//                if (response.getCode() == ApiConstants.unregister) {
//                    requestRegister(loginParams.getUsername());
//                } else {
//                    logout();
//                }
//            }
        }
    };

    private RegisterRequest registerRequest = new RegisterRequest() {
        @Override
        protected void onRegisterSuccess(RegisterResponse registerResponse) {
            //首次注册成功直接调用登录
            requestLogin(false, getSuccessCall(), getReAuditCall());
        }

        @Override
        protected void onFail(ExceptionResponse response, RegisterParams registerParams, Object extra) {
            if (response.getCode() == ApiConstants.userAlreadyExists) {
                requestLogin(false, null, null);
            } else {
                UserUtils.getInstance().clear();
                Action0 reAuditCall = getReAuditCall();
                if (reAuditCall != null) {
                    reAuditCall.call();
                }
            }
        }
    };

    //开始登录授权
    public void startAuthorization(Context context, LifecycleOwner lifecycleOwner, Action0 authSuccessCall, Action0 reAuditCall) {
        this.context = context;
        this.lifecycleOwner = lifecycleOwner;
        if (UserUtils.getInstance().isLogin() && isValidToken()) {
            if (authSuccessCall != null) {
                authSuccessCall.call();
            }
        } else {
            requestLogin(false, authSuccessCall, reAuditCall);
        }
    }

    public void silentAuthorization(Context context, LifecycleOwner lifecycleOwner, Action0 successCall) {
        this.context = context;
        this.lifecycleOwner = lifecycleOwner;
        requestLogin(true, successCall, null);
    }

    private String genderUserName(String deviceId) {
        if (UserUtils.getInstance().isEnableDebugAccount()) {
            return UserUtils.getInstance().getDebugAccount().getAccount();
        }
        int code = deviceId.hashCode();
        String userCode = code > 0 ? String.valueOf(code) : String.format("%s1", Math.abs(code));
        return String.format("%s@aic.com", userCode);
    }

    private String getUserPassword() {
        if (UserUtils.getInstance().isEnableDebugAccount()) {
            return UserUtils.getInstance().getDebugAccount().getPassword();
        }
        return UserUtils.getInstance().getFormalPassword();
    }

    private void requestLogin(boolean silent, Action0 successCall, Action0 reAuditCall) {
        String deviceId = DeviceUtils.getInstance().getDeviceId(context);
        LoginParams loginParams = new LoginParams();
        loginParams.setUsername(genderUserName(deviceId));
        loginParams.setPassword(getUserPassword());
        loginParams.setDeviceId(deviceId);
        loginRequest.setSuccessCall(successCall);
        loginRequest.setReAuditCall(reAuditCall);
        loginRequest.request(context, lifecycleOwner, loginParams, silent);
    }

    private boolean isValidToken() {
        UserInfo userInfo = UserUtils.getInstance().getUserInfo();
        long loginTime = userInfo.getLoginTime();
        long diff = System.currentTimeMillis() - loginTime;
        int expiresIn = (int) (userInfo.getExpiresIn() * 1000 * 0.75);
        return diff < expiresIn;
    }

    //token续期
    public void tokenRenewal() {
        if (!UserUtils.getInstance().isLogin()) {
            return;
        }
        if (!tokenInRenewal && !isValidToken()) {
            tokenInRenewal = true;
            String accessToken = UserUtils.getInstance().getAccessToken();
            RefreshTokenParams refreshTokenParams = new RefreshTokenParams(accessToken);
            refreshTokenRequest.request(context, lifecycleOwner, refreshTokenParams);
        }
    }

    private RefreshTokenRequest refreshTokenRequest = new RefreshTokenRequest() {
        @Override
        protected void onRefreshTokenCall(RefreshTokenResponse response) {
            UserInfo info = new UserInfo();
            info.setAccessToken(response.getAccessToken());
            info.setExpiresIn(response.getExpiresIn());
            UserUtils.getInstance().saveUserInfo(info);
        }

        @Override
        protected void onRefreshTokenEnd() {
            tokenInRenewal = false;
        }
    };

    public void refreshTokenRenewal(Context context, LifecycleOwner lifecycleOwner) {
        if (!UserUtils.getInstance().isLogin()) {
            return;
        }
        this.context = context;
        this.lifecycleOwner = lifecycleOwner;
        UserInfo userInfo = UserUtils.getInstance().getUserInfo();
        long loginTime = userInfo.getLoginTime();
        long diff = System.currentTimeMillis() - loginTime;
        long refreshTime = 30 * 24 * 3600 * 750;
        if (diff < refreshTime) {
            return;
        }
        requestLogin(true, null, null);
    }

    /**
     * 启动授权定时检测，在授权成功后再调用此方法
     * 在accessToken有效范围内确保对refreshToken续期检测执行再次，以免应用退到后台时accessToken失效
     */
    public void startAuthorizationTimingDetection() {
        if (authorizationCheckExecutor.isRunning() || !UserUtils.getInstance().isLogin()) {
            return;
        }
        authorizationCheckExecutor.setPeriod(checkPeriod);
        authorizationCheckExecutor.start();
    }

    private long getLastCheckTime() {
        if (lastCheckTime > 0) {
            return lastCheckTime;
        }
        lastCheckTime = MPLocalKV.getInstance().getLong("lastCheckTimeKey", 0);
        return lastCheckTime;
    }

    private CycleExecutor authorizationCheckExecutor = new CycleExecutor() {
        @Override
        protected void onDoingWithThread(Object params) {
            long checkTime = getLastCheckTime();
            long currentTime = System.currentTimeMillis();
            long diff = currentTime - checkTime;
            if (diff < checkPeriod) {
                return;
            }
            tokenRenewal();
            lastCheckTime = currentTime;
            MPLocalKV.getInstance().put("lastCheckTimeKey", currentTime);
        }
    };
}
